#include <bits/stdc++.h>
using namespace std;

// 【题目】力扣209. 长度最小的子数组
// 【难度】中等
// 【提交】 https://leetcode.cn/problems/minimum-size-subarray-sum/description/
// 【标签】滑动窗口；数组；双指针
class Solution_LC0209 {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        int i = 0, j = 0, ans = INT_MAX, sum = 0;
        
        // 滑动窗口遍历数组
        while (j < n) {
            // 扩展右边界，累加元素值
            sum += nums[j];
            
            // 当窗口和大于等于目标值时，尝试收缩左边界
            while (sum >= target) {
                // 更新最小长度
                ans = min(ans, j - i + 1);
                // 收缩左边界，减去左边界元素
                sum -= nums[i];
                i++;
            }
            j++;
        }
        return ans == INT_MAX ? 0 : ans;
    }
};

/**
 * @brief 学习总结：
 * 本题是经典的滑动窗口问题，要求找到和至少为target的最短连续子数组。
 * 
 * 解题思路：
 * 1. 使用双指针i和j维护滑动窗口
 * 2. 右指针j扩展窗口，累加元素值
 * 3. 当窗口和≥target时，记录窗口长度并收缩左指针i
 * 4. 遍历完成后返回最小长度，若无满足条件的子数组则返回0
 * 
 * 算法分析：
 * - 时间复杂度：O(n)，每个元素最多被访问两次（左右指针各一次）
 * - 空间复杂度：O(1)，只使用了常数级别的额外空间
 * 
 * 优点：
 * - 滑动窗口思路清晰，代码简洁高效
 * - 使用双指针避免了暴力解法的重复计算
 * - 边界条件处理得当，考虑了无解情况
 * 
 * 改进建议：
 * 1. 变量命名可以更具描述性：
 *    - 将i改为left，j改为right
 *    - 将ans改为minLength
 * 
 * 2. 添加输入验证：
 *    if (nums.empty()) return 0;
 * 
 * 3. 优化版本（提高可读性）：
 * 
 * int minSubArrayLen(int target, vector<int>& nums) {
 *     int left = 0, right = 0;
 *     int sum = 0, minLength = INT_MAX;
 *     int n = nums.size();
 *     
 *     while (right < n) {
 *         sum += nums[right];
 *         
 *         while (sum >= target) {
 *             minLength = min(minLength, right - left + 1);
 *             sum -= nums[left];
 *             left++;
 *         }
 *         right++;
 *     }
 *     return minLength == INT_MAX ? 0 : minLength;
 * }
 * 
 * 4. 考虑特殊情况：
 *    - 如果数组总和小于target，可以直接返回0
 *    - 如果存在单个元素≥target，最小长度就是1
 * 
 * 核心思想：
 * 滑动窗口是处理连续子数组和问题的有效方法，通过动态调整窗口边界，
 * 在O(n)时间内找到最优解，避免了O(n²)的暴力枚举。
 * 
 * 应用场景：
 * - 和至少为K的最短子数组
 * - 乘积小于K的子数组
 * - 包含所有字符的最短子串
 * - 最大连续1的个数等
 */